<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>精灵模型Sprite模拟下雨效果</title>
    <script src="http://www.yanhuangxueyuan.com/versions/threejsR92/build/three.js"></script>
    <script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/controls/OrbitControls.js"></script>
    <link rel="stylesheet" href="common.css">
</head>

<body>
</body>
<script>
    // 创建场景
    let scene = new THREE.Scene();
    var plane = createPlaneGeometryBasicMaterial(); //创建草地
    scene.add(plane);

    // 【批量创建精灵模型】
    var treeSpriteGroup = new THREE.Group() //创建一个组，用来存放tree精灵模型
    var rainSpriteGroup = new THREE.Group() //创建一个组，用来存放rain精灵模型
    for (let i = 0; i < 100; i++) {
        creatRainSpriteMesh(i);
        creatTreeSpriteMesh(i);
    }
    scene.add(treeSpriteGroup, rainSpriteGroup); //将精灵组添加到场景中

    // 创建地面
    function createPlaneGeometryBasicMaterial() {
        var textureLoader = new THREE.TextureLoader();
        var cubeMaterial = new THREE.MeshStandardMaterial({
            map: textureLoader.load("image/floor.jpg"),
        });
        var planeGeometry = new THREE.PlaneGeometry(2000, 1000);
        var plane = new THREE.Mesh(planeGeometry, cubeMaterial);
        plane.rotation.x = -Math.PI / 2
        plane.position.y = 0;
        return plane;
    }

    // 创建rain精灵模型
    function creatRainSpriteMesh(i) {
        var spriteMaterial1 = new THREE.SpriteMaterial({
            map: new THREE.TextureLoader().load("image/rain.png"),
        })
        var sprites = new THREE.Sprite(spriteMaterial1)
        sprites.scale.set(8, 10, 1);;
        sprites.name = "RainSprite_" + i; //命名每个精灵
        var k1 = Math.random() - 0.5;
        var k2 = Math.random() - 0.5;
        var k3 = Math.random();
        sprites.position.set(1500 * k1, 800 * k3, 800 * k2) //随机精灵位置
        rainSpriteGroup.add(sprites) //将每个rain精灵模型放入组中
    }

    // 创建tree精灵模型
    function creatTreeSpriteMesh(i) {
        var spriteMaterial2 = new THREE.SpriteMaterial({
            map: new THREE.TextureLoader().load("image/tree.png"),
        })
        var sprites = new THREE.Sprite(spriteMaterial2)
        sprites.scale.set(100, 100, 1);;
        sprites.name = "TreeSprite_" + i; //命名每个精灵
        var k1 = Math.random() - 0.5;
        var k2 = Math.random() - 0.5;
        sprites.position.set(1000 * k1, 50, 1000 * k2) //随机精灵位置
        treeSpriteGroup.add(sprites) //将每个tree精灵模型放入组中
    }

    // 光源
    let AmbientLight = new THREE.AmbientLight(0xffffff);
    scene.add(AmbientLight);

    // 相机
    var width = window.innerWidth; //窗口宽度
    var height = window.innerHeight; //窗口高度
    camera = new this.THREE.PerspectiveCamera(45, width / height, 1, 10000)
    camera.position.set(0, 150, 1000) // 设置相机位置
    camera.lookAt(new this.THREE.Vector3(0, 0, 0)); // 设置相机方向(指向的场景对象)
    var axisHelper = new THREE.AxisHelper(600); // 辅助坐标系
    scene.add(axisHelper);

    // 渲染
    var renderer = new THREE.WebGLRenderer();
    document.body.appendChild(renderer.domElement); //body元素中插入canvas对象
    renderer.setSize(width, height); //设置渲染区域尺寸
    renderer.setClearColor(0x00ffff, 0.5) // 设置背景颜色


    // 雨滴动画
    var needRun;
    var controls = new THREE.OrbitControls(camera, renderer.domElement)

    function render(needRun) {
        needRun = true;
        if (needRun) {
            needRun = false;
            rainSpriteGroup.children.forEach(sprite => {
                sprite.position.y -= 3; // 雨滴的y坐标每次减1
                if (sprite.position.y <= 0) {
                    // 如果雨滴落到地面，重置y，从新下落
                    sprite.position.y = 800 * (Math.random());
                }
            });
            renderer.render(scene, camera);
            requestAnimationFrame(render);
        }
    }

    controls.addEventListener('change', (e) => {
        if (needRun) {
            needRun = false
            requestAnimationFrame(render)
        }
    }, false)

    render()
</script>

</html>